package znet

import (
	"errors"
	"fmt"
	"io"
	"net"
	"tcpChat/conf"
	"tcpChat/ziface"
	"time"
)

type Connection struct {
	TcpServer ziface.IServer //当前的CONN属于那个server

	Conn    *net.TCPConn //SOCKET套接字
	ConnId  uint32       //tcp ID
	IsClose bool         // 状态

	MsgHandler ziface.IMsgHandler //处理的方法router

	//告知该链接已经退出/停止的channel
	ExitBuffChan chan bool

	//无缓冲管道，用于读写两个goroutine之间的消息通信
	MsgChan chan []byte

	//有缓冲管道
	MsgBuffChan chan []byte
}

//创建连接方法
func NewConnection(server ziface.IServer, conn *net.TCPConn, connId uint32, handler ziface.IMsgHandler) *Connection {
	c := &Connection{
		TcpServer:    server,
		Conn:         conn,
		ConnId:       connId,
		IsClose:      false,
		MsgHandler:   handler,
		ExitBuffChan: make(chan bool, 1),
		MsgChan:      make(chan []byte),
		MsgBuffChan:  make(chan []byte, conf.GlobalObject.MaxMsgChanLen),
	}

	//将conn加入到server的connManager中
	c.TcpServer.GetConnManager().Add(c)

	return c
}

func (c *Connection) StartWrite() {
	fmt.Println("[Writer Goroutine is Running]")

	for {
		select {
		case data := <-c.MsgChan:
			if _, err := c.GetConnection().Write(data); err != nil {
				fmt.Println(fmt.Sprintf("服务端发送数据失败： %s", string(data)))
				return
			}

		case data, ok := <-c.MsgBuffChan:
			if ok == false {
				fmt.Println(fmt.Sprintf("CONNECT[%d] 获取管道数据失败", c.GetConnId()))
				continue
			}
			if _, err := c.GetConnection().Write(data); err != nil {
				fmt.Println(fmt.Sprintf("服务端发送数据失败： %s", string(data)))
				return
			}
		case <-c.ExitBuffChan:
			return

		}
	}
}

func (c *Connection) SendMsg(msgId uint32, data []byte) error {
	if c.IsClose == true {
		return errors.New("Connect IS Close")
	}

	msg, err := NewDataPack().Pack(NewMessage(msgId, data))

	if err != nil {
		return err
	}
	//写入管道
	c.MsgChan <- msg

	return nil
}

func (c *Connection) SendBuffMsg(msgId uint32, data []byte) error {
	if c.IsClose == true {
		return errors.New(fmt.Sprintf("Connect [%d] IS CLOSE", c.GetConnId()))
	}

	msg, err := NewDataPack().Pack(NewMessage(msgId, data))
	if err != nil {
		return err
	}
	//写入缓冲管道
	c.MsgBuffChan <- msg

	return nil
}

func (c *Connection) StartReader() {
	fmt.Println("读取数据线程.......\n")

	defer c.Stop() //处理连接的状态

	for {
		dataPack := NewDataPack()

		//先解析head数据
		headBuf := make([]byte, dataPack.GetHeadLen())
		_, err := io.ReadFull(c.GetConnection(), headBuf)
		if err != nil {
			fmt.Println("读取数据失败", err.Error())
			c.ExitBuffChan <- true
			continue
		}

		message, err := dataPack.UnPack(headBuf)
		if err != nil {
			fmt.Println("数据包解析失败", err.Error())
			c.ExitBuffChan <- true
			continue
		}

		//获取body字节流
		var bodyBuf []byte
		if message.GetDataLen() > 0 {
			bodyBuf = make([]byte, message.GetDataLen())
			_, err = io.ReadFull(c.GetConnection(), bodyBuf)
			if err != nil {
				fmt.Println("数据包解析body失败", err.Error())
				c.ExitBuffChan <- true
				continue
			}
		}
		message.SetData(bodyBuf)
		fmt.Printf("MSG: ID=%d, len= %d, data= %s \n", message.GetMSGId(), message.GetDataLen(), string(message.GetData()))

		// 网络对象
		req := Request{
			Conn:    c,
			Message: message,
		}
		if conf.GlobalObject.WorkerPoolSize > 0 {
			c.MsgHandler.SendMsgToTaskQueue(&req)
		} else {
			go c.MsgHandler.DoMsgHandler(&req)
		}

		time.Sleep(time.Second)
	}
}

/**
 * 使用管道阻塞消息
 *  启动连接。当前任务运行
 */
func (c *Connection) Start() {

	//开启携程从客户端读取数据
	go c.StartReader()

	//向客户端写入数据
	go c.StartWrite()

	select {
	case <-c.ExitBuffChan:
		return
	}
}

// 停止工作，修改socket状态
func (c *Connection) Stop() {
	if c.IsClose == true {
		return
	}

	c.IsClose = true

	//关闭socket连接
	c.Conn.Close()

	//通知缓冲队列读取数据
	c.ExitBuffChan <- true

	//将链接从管理器中删除
	c.TcpServer.GetConnManager().Remove(c)

	//关闭管道
	close(c.ExitBuffChan)
	close(c.MsgBuffChan)
}

func (c *Connection) GetConnection() *net.TCPConn {
	return c.Conn
}

func (c *Connection) GetConnId() uint32 {
	return c.ConnId
}

func (c *Connection) GetRemoteAddr() net.Addr {
	return c.Conn.RemoteAddr()
}
